/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.taglibs.input;

import com.codemagi.util.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.*;
import org.apache.log4j.*;

/**
 *  This class implements the &lt;input:dateselect&gt; tag, which presents 
 *  three &lt;select&gt; form elements for month/day/year.
 *
 *  Note that this class has been largely superseded by the Calendar tag. 
 *  This class is not yet deprecated, though it may be at some time in the future.
 *
 *  @version 1.0
 *  @author August Detlefsen for CodeMagi, Inc.
 *  @deprecated User Calendar instead
 */
public class DateSelect extends Input {

    //set to true to show debug output
    Logger log = Logger.getLogger(this.getClass());

    // what are our options? :)
    private OrderedTable dayOptions   = Util.DAYS;	
    private OrderedTable monthOptions = Util.MONTHS;
    private OrderedTable yearOptions  = Util.YEARS;

    private Date defaultDate;           // default date

    private boolean showDays   = true;
    private boolean showMonths = true;
    private boolean showYears  = true;

    private ServletRequest req;


    //GETTERS AND SETTERS

    public void setDefault(Date x) {
	log.debug("DateSelect.setDefault() Date to: " + x);
	defaultDate = x;
    }

    public void setDayOptions(OrderedTable x) {
	dayOptions = x;
    }

    public void setMonthOptions(OrderedTable x) {
        monthOptions = x;
    }

    public void setYearOptions(OrderedTable x) {
        yearOptions = x;
    }

    public void setShowdays(boolean x) {
        showDays = x;
    }
    
    public void setShowmonths(boolean x) {
        showMonths = x;
    }
    
    public void setShowyears(boolean x) {
        showYears = x;
    }
    

    private String makeSelect(String tagName, OrderedTable tagOptions, String defaultValue) 
	throws JspTagException, java.io.IOException {

	StringBuffer tag = new StringBuffer();

	//start the select list
	tag.append("<SELECT NAME=\"" + Util.quote(tagName) +"\"");

	//disable the form field if disabled is set
	if (disabled) {
	    tag.append("    readonly=\"readonly\"");
	    tag.append("    OnFocus=\"blur();\"");
	    appendAttribute("style", "cursor:default;");
	}

	// include any attributes we've got here
	Util.printAttributes(tag, attributes);

	//if this is a required field and it is not filled out, do something...
	if ( !Utils.isEmpty((String)req.getAttribute("error_" + name + "_error")) ) {
                tag.append("    class=\"cminput_error\"");
            }

	// end the starting tag
	tag.append(">");

	//make the options
	makeOptions(tagOptions, tag, tagName, defaultValue);

	//add the ending tag
	tag.append("</SELECT>");

	//return
	return tag.toString();
    }


    /*
     * Print out our options, selecting one or more if appropriate.
     * If there are multiple selections but the page doesn't call
     * for a <select> that accepts them, ignore the selections.
     * This is preferable to throwing a JspException because the
     * (end) user can control input, and we don't want the user
     * causing exceptions in our application.
     */
    private void makeOptions(OrderedTable options, StringBuffer out, String name, String defaultValue) 
	throws JspTagException {

	if (options == null) {
	    //exception - no way to make a valid tag
	    throw new JspTagException("invalid select: no options");   
	}

	// get the current selection
	String[] selected = getParameterValues(name, (HttpServletRequest)req);

	if (selected != null && selected.length > 1) {
	    //should we throw an exception here instead?
	    throw new JspTagException("invalid select: " + name + " too many options selected");
	}

	//get the selected value 
	String chosen = "";
	if (selected != null && !com.codemagi.util.Utils.isEmpty(selected[0]) ) { 
	    chosen = selected[0];
	} else if ( !com.codemagi.util.Utils.isEmpty(defaultValue) ) {
	    chosen = defaultValue;
	}	

	// actually print the <option> tags
	Collection c = (Collection)(options.orderedKeys());
	Iterator i   = c.iterator();
	
	while (i.hasNext()) {

	    String key;
	    String value;

	    try {
		key   = (String)i.next();
		value = (String)options.get(key);
	    } catch (ClassCastException cce) {
		/* If the option contains non-Strings, give the user
		 * a more meaningful message than what he or she would get
		 * if we just propagated a ClassCastException back.
		 */
		throw new JspTagException("all members in options Map must be Strings");
	    }

	    // use key if value is null
	    if (value == null) value = key;	
	    
	    //start the OPTION tag
	    out.append("<OPTION VALUE=\"" + Util.quote(key) + "\"");

            if ( key.equals(chosen) ) {
		out.append(" SELECTED");
	    }

	    out.append(">");
	    out.append(Util.quote(value));
	    out.append("</OPTION>\n");
	}

	//no need to return -all work appended to buffer

    }


    public int doStartTag() throws JspException {
	log.debug("DateSelect: starting doStartTag");

	try {
	    // sanity check
	    if (name == null || name.equals("")) {
		throw new JspTagException("invalid null or empty 'name'");
	    }

	    // get what we need from the page
	    log.debug("DateSelect: getting request and out");
	    req = pageContext.getRequest();
	    JspWriter out = pageContext.getOut();

	    //determine the defaults
	    log.debug("DateSelect: determining defaults");
	    String defaultDay   = null;
	    String defaultMonth = null;
	    String defaultYear  = null;

	    if (defaultDate != null) {

		defaultDay   = DateUtils.formatDate(defaultDate, DateUtils.DAY_DIGITS);
		defaultMonth = DateUtils.formatDate(defaultDate, DateUtils.MONTH_DIGITS);
		defaultYear  = DateUtils.formatDate(defaultDate, DateUtils.YEAR);
		
		log.debug("DateSelect: Default date: " + defaultDay + "/" + defaultMonth + "/" + defaultYear);
	    }
	    log.debug("DateSelect: ...done");

	    //start the formatting
	    out.println("<TABLE BORDER=\"0\" CELLSPACING=\"2\" CELLPADDING=\"0\" CLASS=\"cminput_dateselect\"><TR><TD>");

	    //make the month Tag
	    log.debug("DateSelect: making month tag");
	    if (showMonths) {
		out.println( makeSelect( Util.quote("month_" + name + "_month"), monthOptions, defaultMonth ) );
	    } else {
		out.println( "<INPUT TYPE=\"hidden\" NAME=\"" + Util.quote("month_" + name + "_month") +
			     "\" VALUE=\"" + defaultMonth + "\">" );
	    }
	    out.println("</TD><TD>");

	    //make the day Tag
	    log.debug("DateSelect: making day tag");
	    if (showDays) {
		out.println( makeSelect( Util.quote("day_" + name + "_day"), dayOptions, defaultDay ) );
	    } else {
		out.println( "<INPUT TYPE=\"hidden\" NAME=\"" + Util.quote("day_" + name + "_day") +
			     "\" VALUE=\"" + defaultDay + "\">" );
	    }

	    out.println("</TD><TD>");

	    //make the year tag
	    log.debug("DateSelect: making year tag");
	    if (showYears) {
		out.println( makeSelect( Util.quote("year_" + name + "_year"), yearOptions, defaultYear ) );
	    } else {
		out.println( "<INPUT TYPE=\"hidden\" NAME=\"" + Util.quote("year_" + name + "_year") +
			 "\" VALUE=\"" + defaultYear + "\">" );
	    }
	    out.println("</TD></TR></TABLE>");

	    //show the years message
            if (showError) {
                String errorMessage = (String)req.getAttribute(name + "_error_message");
                if (errorMessage != null && !"".equals(errorMessage) ) {
                    out.print( "<BR><SPAN CLASS=\"input_error_msg\">" + errorMessage + "</SPAN>");
                }
            }

	    log.debug("DateSelect: finished doStartTag");

	} catch (Exception ex) {
	    log.debug("DateSelect: EXCEPTION IN DOSTARTTAG");
	    log.debug("", ex);

	    throw new JspTagException(ex.getMessage());
	}
	return SKIP_BODY;
    }

}







